package com.yky.filter;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yky.constant.TokenConstant;
import com.yky.utils.PatternUtils;
import com.yky.utils.SmUtils;
import com.yky.vo.Result;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lrl
 */
@Component
public class ResponseEncryptFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(ResponseEncryptFilter.class);

    @Value("${yky.sm4.encrypt}")
    private Boolean encrypt;
    @Value("${yky.sm4.ignoreUrl}")
    private List<String> ignoreUrl = new ArrayList<>();
    @Value("${sa-token.token-name}")
    private String tokenName = TokenConstant.HEADER;
    private static final Integer MINIMUM = 0;
    private static final Integer MAXIMUM = 16;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        PrintWriter out = null;
        String uri = httpRequest.getRequestURI();
        String [] uris = new String[ignoreUrl.size()];
        boolean flag = PatternUtils.matchList(ObjectUtil.isNotEmpty(ignoreUrl) ? ignoreUrl.toArray(uris) : null, uri);
        if (flag || !encrypt) {
            try {
                chain.doFilter(httpRequest, httpResponse);
            } catch (IOException | ServletException e) {
                e.printStackTrace();
            }
        } else {
            try {
                //响应处理  包装响应对象 res 并缓存响应数据
                ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
                //执行业务逻辑 交给下一个过滤器或servlet处理
                chain.doFilter(request, responseWrapper);
                //设置响应内容格式，防止解析响应内容时出错
                responseWrapper.setContentType("application/json;charset=UTF-8");
                //获取响应数据
                byte[] resData = responseWrapper.getResponseData();
                String resDataStr = new String(resData, StandardCharsets.UTF_8);
                if (StringUtils.isNotBlank(resDataStr)) {
                    ObjectMapper mapper = new ObjectMapper();
                    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
                    resDataStr = mapper.writeValueAsString(JSONObject.parse(resDataStr));
                }

                //获取token
                String token = getToken(httpRequest);
                JSONObject json = new JSONObject();
                if (StringUtils.isBlank(token) || StringUtils.equals("undefined", token) || !encrypt) {
                    json.put("data", JSONObject.parseObject(resDataStr));
                } else {
                    String resultstr = "";
                    //截取前16位作为加密秘钥
                    String key = token.substring(MINIMUM, MAXIMUM);
                    //SM4加密
                    resultstr = SmUtils.encryptEcb(key, resDataStr);
                    json.put("data", resultstr);
                }
                response.reset();
                response.setContentType("application/json;charset=UTF-8");
                out = response.getWriter();
                out.print(json);
                out.flush();
            } catch (Exception e) {
                try {
                    getFailResponse((HttpServletResponse) response);
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    @Override
    public void destroy() {

    }

    private void getFailResponse(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            //加密后的错误消息
            out.write(JSONObject.toJSONString(Result.error("数据加密异常")));
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 获取请求token
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(tokenName);
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstant.TOKEN_PREFIX)) {
            token = token.replace(TokenConstant.TOKEN_PREFIX, "");
        }
        return token;
    }

    /**
     * 哪些路径不处理
     *
     * @param request
     * @param strArr
     * @return
     */
    public boolean isIgnore(HttpServletRequest request, List<String> strArr) {
        String path = request.getRequestURI();
        System.out.println(path);
        for (String ignore : strArr) {
            if (path.contains(ignore)) {
                return true;
            }
        }
        return false;
    }
}
